/**
 * Samsung Project
 * Copyright (c) 2007-2008 Mobile XG, Samsung Electronics, Inc.
 * All right reserved.
 *
 * This software is the confidential and proprietary information
 * of Samsung Electronics Inc. ("Confidential Information"). You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Samsung Electronics.
 */

/**
 * @file	SysUtility.h
 * @brief	This is the header file for the functions depended by system.
 * @author	Thomas, Kim
 * @version	1.5
 */
 
/****************************************************************************
 *  INCLUDES
 ****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "system.h"
#include "library.h"

#include "fgl.h"
#include "Config.h"
#include "SysUtility.h"

//#include "intc.h"
//#include "dma.h"


unsigned int fglSysReadReg( unsigned int addr )
{
	return (unsigned int)(*((volatile unsigned int*)addr));
}


static void fglSysWriteReg ( unsigned int addr, unsigned int val )
{
	(*(volatile unsigned int *)(addr) = (unsigned int)(val));
}



void fglSysTransferToPort (
							unsigned int	*psrc_data, 
							unsigned int	pdst_port, 
							unsigned int 	 size 
						  )
{
	unsigned int offset = (unsigned int)psrc_data & 0x0000001F;
	unsigned int alloc_size = 0;

	if(psrc_data == 0 || pdst_port == 0 || size == 0)
	{
		// For debug
		//WRITEREG(0x00000104, 0xFFFFFFFF);
		return;
	}

	do
	{
		do
		{
			alloc_size = fglSysReservePortAlloc(size, 1);
		} while (alloc_size == 0);
		
		/* Write out dwords until we reach 32-byte alignment */
		if (offset > 0)
		{
			unsigned int before_align = 8 - (offset >> 2);

			if (before_align > alloc_size)
			{
				before_align = alloc_size;
				alloc_size = 0;
			}
			else
			{
				alloc_size -= before_align;
			}

			while (before_align-- > 0)
			{
				fglSysWriteReg(pdst_port, *(psrc_data++));
				size --;
			}
			offset = (unsigned int)psrc_data & 0x0000001F;			
		}

		/* This works on aligned data */
		while (alloc_size & 0xFFFFFFF8)
		{

#if TARGET_PLATFORM == WIN32_VIP 
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));
			fglSysWriteReg(pdst_port, *(psrc_data++));

#elif TARGET_PLATFORM == FPGA_BOARD
            unsigned int a0, a1, a2, a3, a4, a5, a6, a7;
			__asm
			{
    			LDMIA psrc_data!,{a0, a1, a2, a3, a4, a5, a6, a7}
    			STMIA pdst_port, {a0, a1, a2, a3, a4, a5, a6, a7}
    			//LDMIA psrc_data!,{v1-v8}
    			//STMIA pdst_port,{v1-v8}
			}
#endif
			alloc_size -= 8;
			size -= 8;
		}
	} while (size & 0xFFFFFFF8);

	/* Write out the last < 8 dwords */
	while (size-- > 0)
	{
		fglSysWriteReg(pdst_port, *psrc_data);
		++psrc_data;
	}
}



void 
fglSysTransferToPort (
							unsigned int	*psrc_data, 
							unsigned int 	size 
						)
{
	//unsigned int *pdst_port = FGHI_DWENTRY; 

	unsigned int offset = (unsigned int)psrc_data & 0x0000001F;
	unsigned int alloc_size = 0;

	if(psrc_data == 0 || size == 0)
	{
		// For debug
		//WRITEREG(0x00000104, 0xFFFFFFFF);
		return;
	}

	do
	{
		do
		{
			alloc_size = fglSysReservePortAlloc(size, 1);
		} while (alloc_size == 0);
		
		/* Write out dwords until we reach 32-byte alignment */
		if (offset > 0)
		{
			unsigned int before_align = 8 - (offset >> 2);

			if (before_align > alloc_size)
			{
				before_align = alloc_size;
				alloc_size = 0;
			}
			else
			{
				alloc_size -= before_align;
			}

			while (before_align-- > 0)
			{
				fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
				size --;
			}
			offset = (unsigned int)psrc_data & 0x0000001F;			
		}

		/* This works on aligned data */
		while (alloc_size & 0xFFFFFFF8)
		{

#if TARGET_PLATFORM == WIN32_VIP 
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));
			fglSysWriteReg(FGHI_DWENTRY, *(psrc_data++));

#elif TARGET_PLATFORM == FIRMWARE
            unsigned int a0, a1, a2, a3, a4, a5, a6, a7;
			__asm
			{
    			LDMIA psrc_data!,{a0, a1, a2, a3, a4, a5, a6, a7}
    			STMIA FGHI_DWENTRY, {a0, a1, a2, a3, a4, a5, a6, a7}
    			//LDMIA psrc_data!,{v1-v8}
    			//STMIA pdst_port,{v1-v8}
			}
#endif

			alloc_size -= 8;
			size -= 8;
		}
	} while (size & 0xFFFFFFF8);

	/* Write out the last < 8 dwords */
	while (size-- > 0)
	{
		fglSysWriteReg(FGHI_DWENTRY, *psrc_data);
		++psrc_data;
	}
}


unsigned int 
fglSysReservePortAlloc(
						 unsigned int	request_slots, 
						 unsigned int	preferred_min 
					  )
{
	unsigned int allocate_slots = 0;
	volatile unsigned int free_slots;

	if(request_slots == 0)
	{
		return 0;
	}

    do 
    {
    	free_slots = rFGHI_DWSPACE;
    	allocate_slots = ((free_slots < request_slots) ? free_slots : request_slots);
    } while(allocate_slots < preferred_min);

	return allocate_slots;
}



void fglSwapBuffer(unsigned int uSelect)
{
	unsigned int  data;
	
	if(uSelect == 0 || uSelect == 1)
	{
	
		READREGP(FIMG_LCDCON1, data);
		data = (data & ~(1<<20)) | uSelect<<20;
		WRITEREG(FIMG_LCDCON1, data);
	}
}


unsigned int 
fglWriteVertexShaderConstFloat( 
                                    unsigned int offset, 
                                    unsigned int size, /* count of float */
                                    float *pdata
                               )
{
    unsigned int ConstFloatAddr = FGVS_CFLOAT;
    
    ConstFloatAddr += (offset * 4);
    
    for(int i = 0; i < size; i++)
    {
        WRITEREGF(ConstFloatAddr, *pdata++);	    
        ConstFloatAddr += 4;
        offset++;
	}
	
	return offset;
}


unsigned int 
fglWriteFragmentShaderConstFloat( 
                                    unsigned int offset, 
                                    unsigned int size, /* count of float */
                                    float *pdata
                                )
{
    unsigned int ConstFloatAddr = FGPS_CFLOAT;
    
    ConstFloatAddr += (offset * 4);
    
    for(int i = 0; i < size; i++)
    {
        WRITEREGF(ConstFloatAddr, *pdata++);	    
        ConstFloatAddr += 4;
        offset++;
	}
	
	return offset;
}

void fglDumpContext(const char *pFileName)
{
	int i = 0;
	int size = 0;

	unsigned int read_reg = 0;
	pdefault_reg p_default_reg = 0;

    pdefault_reg reg_groups[8] = 
    {
        (pdefault_reg)gb_default_regs,    
        (pdefault_reg)hi_default_regs,    
        (pdefault_reg)vs_default_regs,    
        (pdefault_reg)pe_default_regs,
        (pdefault_reg)ra_default_regs,    
        (pdefault_reg)ps_default_regs,    
        (pdefault_reg)tu_default_regs,    
        (pdefault_reg)pf_default_regs
    };
    
    unsigned int reg_size[8] = 
    {
        gb_reg_count,   
        hi_reg_count,   
        vs_reg_count,   
        pe_reg_count,
        ra_reg_count,   
        ps_reg_count,   
        tu_reg_count,   
        pf_reg_count
    };
#if defined(SEMIHOSTING)
	
 	FILE * fp = fopen(pFileName, "wb");

	if (fp != 0)
	{
        
        for(i = 0; i < 8; i++)
        {
            //p_default_reg = (pdefault_reg)dump_reg_group[i].regs;
            //size = (unsigned int)dump_reg_group[i].size;
            p_default_reg = (pdefault_reg)reg_groups[i];
            size = reg_size[i];
       	    do
        	{
        		if(p_default_reg->writable)
        		{
                    //read_reg = READREG(p_default_reg->reg.addr);
                    READREGP(p_default_reg->reg.addr, read_reg);
                   // if(read_reg != 0)
                        fprintf(fp, "0x%08X 0x%08X\n", p_default_reg->reg.addr, read_reg);
        		}

        		++p_default_reg;

        	} while(--size != 0);        
        }
	}
	
	fclose(fp);
	
#else /* SEMIHOSTING */

    UART_Printf("\nSemi-hosting is disabled.\n\n");
    
    for(i = 0; i < 8; i++)
    {
        p_default_reg = (pdefault_reg)reg_groups[i];
        size = reg_size[i];
   	    do
    	{
    		if(p_default_reg->writable)
    		{
                READREGP(p_default_reg->reg.addr, read_reg);
                UART_Printf("0x%08X 0x%08X\n", p_default_reg->reg.addr, read_reg);
    		}

    		++p_default_reg;

    	} while(--size != 0);        
    }

#endif 	
}
